/*
 * Miccsnookersim, a snooker simulation with AI
 * Copyright (C) 2009 Enno Ruijters, Frans van den Heuvel, Yannick Thimister,
 * Ali B. Ozmen, Esther Verhoef, Achim Leydecker
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.

 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.awt.event.*;

public class HumanPlayer implements Player
{
	private final static byte S_READY = 0;
	private final static byte S_WAIT_CUE = 1;
	private final static byte S_WAIT_BALL = 2;
	private final static byte S_TERMINATED = 3;
	private byte state;
	private Cue cue;
	private Display display;
	private String name;
	private BallPlacer placer;

	public HumanPlayer(Display d, String name)
	{
		state = S_READY;
		cue = new Cue(d.getTable(), d.getFrame());
		display = d;
		this.name = name;
	}

	public void setTable(Table newTable)
	{
		cue = new Cue(newTable, display.getFrame());
	}

	public Cue getShot()
	{
		synchronized(this) {
			if (state != S_TERMINATED) {
				display.setCue(cue);
				state = S_WAIT_CUE;
			}
		}
		synchronized (cue) {
			try {
				cue.wait();
			} catch (Exception e) { }
		}
		synchronized(this) {
			if (state != S_TERMINATED) {
				display.setCue(null);
				state = S_READY;
			}
		}
		return cue;
	}

	class BallPlacer extends MouseAdapter{
		private Ball cueBall;
		private Display callingDisplay; /* The display object on which we are listening */
		private Table table;

		public BallPlacer(Ball b, Display d, Table t)
		{
			cueBall = b;
			callingDisplay = d;
			table = t;
		}
		public void mouseClicked(MouseEvent e){
			double xPos = e.getX() / Display.PIXELS_PER_CM;
			double yPos = e.getY() / Display.PIXELS_PER_CM;

			if(xPos>(Table.createBaulkLine().getX1()+Display.xOffset/Display.PIXELS_PER_CM))
			{
				boolean goodPosition = true;
				double centerY = ((Table.createBaulkLine().getY1() + Display.yOffset/Display.PIXELS_PER_CM)
						+ (Table.createBaulkLine().getY2() + Display.yOffset/Display.PIXELS_PER_CM)) / 2.0;
				double xDistance = xPos - (Table.createBaulkLine().getX1() + Display.xOffset/Display.PIXELS_PER_CM);
				double yDistance = Math.abs(yPos - centerY);
				double distanceToCenter = Math.sqrt(xDistance*xDistance + yDistance*yDistance);


				if(distanceToCenter<Table.getTableWidth()/12) {
					cueBall.setPosition(new Vector(xPos-Display.xOffset/Display.PIXELS_PER_CM, yPos-Display.yOffset/Display.PIXELS_PER_CM,0));
					for (Ball b : table.getBalls()) {
						if (b != cueBall &&
								Physics.areColliding(b, cueBall))
							goodPosition = false;
					}
					if (goodPosition) {
						callingDisplay.drawTable();
						table.replaceBall(cueBall);
						Log.logMessage("Ball placed:");
						Log.logVector(cueBall.getPosition());
						synchronized(this) {
							notifyAll();
						}
					} else {
						cueBall.setPosition(new Vector(1.0/0.0,
									1.0/0.0,
									1.0/0.0));
					}
				}
			}
		}
	}    

	public void replaceCueBall(Table table, Ball cueBall)
	{
		placer = new BallPlacer(cueBall, display, table);
		synchronized(this) {
			if (state != S_TERMINATED) {
				display.addMouseListener(placer);
				state = S_WAIT_BALL;
			}
		}
		synchronized(placer) {
			try {
				placer.wait();
			} catch (InterruptedException e) {
				System.exit(1);
			}
		}
		synchronized(this) {
			if (state != S_TERMINATED) {
				display.removeMouseListener(placer);
				state = S_READY;
			}
		}
	}

	public String getName()
	{
		return name;
	}

	public void terminate()
	{
		synchronized(this) {
			switch(state) {
			case S_WAIT_CUE:
				display.setCue(null);
				break;
			case S_WAIT_BALL:
				display.removeMouseListener(placer);
				break;
			}
			state = S_TERMINATED;
		}
	}
}
